﻿''' <summary>
''' 断电现场数据（与Danfoss对比测试时用）
''' </summary>
''' <remarks></remarks>
Public Class PowerTimeClass

    '断电现场数据页地址
    Private Shared _pageAddress As Short = 3750

    '断电现场数据缓存－断电记录列表
    Private Shared _ht As New Hashtable()

    '断电现场数据缓存－原始数据
    Private Shared _htBuf As New Hashtable()

    '断电现场每条记录的长度
    Private Shared ReadOnly _RecordLength As Integer = 10

    ''' <summary>
    ''' 获取断电现场数据列表
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function GetPowerTimeList(ByVal netID As Byte) As IList(Of PowerTimeItem)
        If _ht.Contains(netID) Then
            Return _ht.Item(netID)
        End If

        Dim buf() As Byte
        '读取页数据
        buf = GetBuffer(netID)

        If buf Is Nothing Then
            Return Nothing
        End If

        If Not _htBuf.Contains(netID) Then
            _htBuf.Add(netID, buf)
        End If

        '断电前1小时年
        Dim iYear As Integer

        '断电前1小时月
        Dim iMonth As Integer

        '断电前1小时日
        Dim iDay As Integer

        '断电前1小时小时
        Dim iHour As Integer

        Dim iMinute As Integer
        Dim iSecond As Integer

        '重启时间－日
        Dim iRunDay As Integer

        '重启时间－小时
        Dim iRunHour As Integer

        Dim iRunMinute As Integer
        Dim iRunSecond As Integer

        Dim l As New List(Of PowerTimeItem)

        '当前记录时间的位置索引
        Dim curIndex As Integer
        curIndex = buf(400) '共40个10字节的记录后面的值

        '该页保存最近40个断电现场数据
        For i As Integer = 0 To HIST_LOSTPOWER_RECCOUNT - 1
            'If i = curIndex Then
            '    '当前正在更新的记录,只有断电时间，没有上电时间
            '    'Continue For
            'End If

            iYear = buf(i * _RecordLength + 0)
            iMonth = buf(i * _RecordLength + 1)
            iDay = buf(i * _RecordLength + 2)
            iHour = buf(i * _RecordLength + 3)
            iMinute = buf(i * _RecordLength + 4)
            iSecond = buf(i * _RecordLength + 5)

            iRunDay = buf(i * _RecordLength + 6)
            iRunHour = buf(i * _RecordLength + 7)
            iRunMinute = buf(i * _RecordLength + 8)
            iRunSecond = buf(i * _RecordLength + 9)

            If iYear = 0 Then 'OrElse iRunDay = 0 Then
                '该位置为初始化数据0，没有有效数据。
                Continue For
            End If

            Dim item As New PowerTimeItem()

            '断电时间
            If i = 0 Then '第一条上电记录(只包括上电信息)
                item.StartTime = DateTime.MinValue '记录起始时间为最小时间
                item.EndTime = New DateTime(1900 + iYear, iMonth, iRunDay, iRunHour, iRunMinute, iRunSecond) '第一条断电记录增加保存了年和月数据
            Else
                item.StartTime = New DateTime(1900 + iYear, iMonth, iDay, iHour, iMinute, iSecond)


                Dim dtRun As DateTime

                '记录重启时间和断电日期为同一个月
                dtRun = item.StartTime

                '重启时间
                If iRunDay = 0 OrElse i = curIndex Then '上电时间为0或索引值为当前记录(对当前正在写入数据的断电记录,没有上电时间的情况)
                    item.EndTime = DateTime.MaxValue.AddYears(-1)
                Else

                    If iDay > iRunDay Then
                        'If iDay > iRunDay _
                        '    OrElse (iDay = iRunDay AndAlso iHour > iRunHour) _
                        '    OrElse (iDay = iRunDay AndAlso iHour = iRunHour AndAlso iMinute > iRunMinute) _
                        '    OrElse (iDay = iRunDay AndAlso iHour = iRunHour AndAlso iMinute = iRunMinute And iSecond > iRunSecond) Then

                        '如果重启时间－日 小于断电时间－日 ，判断为重启时间为断电时间的下某个月的日期
                        For j As Integer = 1 To 12  '计算重启时间为断电时间的下几个月,避免出现只增加1个月而导致产生9月31日这样的错误时间
                            dtRun = dtRun.AddMonths(1)
                            If Date.DaysInMonth(dtRun.Year, dtRun.Month) >= iRunDay Then
                                Exit For
                            End If
                        Next

                        ''如果重启时间－日 小于断电时间－日 ，判断为重启时间为断电时间的下个月的日期
                        'dtRun = dtRun.AddMonths(1)
                    Else

                        If Date.DaysInMonth(dtRun.Year, dtRun.Month) < iRunDay Then
                            '重启时间-日 大于断电时间-日, 重启时间超过1个月
                            For j As Integer = 1 To 12  '计算重启时间为断电时间的下几个月,避免出现只增加1个月而导致出现9月31日这样的错误时间
                                dtRun = dtRun.AddMonths(1)
                                If Date.DaysInMonth(dtRun.Year, dtRun.Month) >= iRunDay Then
                                    Exit For
                                End If
                            Next

                        End If

                    End If

                    item.EndTime = New DateTime(dtRun.Year, dtRun.Month, iRunDay, iRunHour, iRunMinute, iRunSecond)
                End If

            End If

            item.EndTime = AdjustDate(item.EndTime)

            l.Add(item)

        Next


        If _ht.Contains(netID) Then
            Return _ht.Item(netID)
        End If


        '添加数据到缓存        
        _ht.Add(netID, l)

        Return l
    End Function

    ''' <summary>
    ''' 调整时间到时间对应页的开始时间
    ''' </summary>
    ''' <param name="dt"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function AdjustDate(ByVal dt As DateTime) As DateTime
        Dim s As Integer
        s = (dt.Hour * 3600 + dt.Minute * 60 + dt.Second) Mod HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE
        Return dt.AddSeconds(-s)
    End Function


    ''' <summary>
    ''' 读取当前存储的历史数据的年月日列表
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetHistoryDataYearMonth(ByVal netID As Byte) As IDictionary(Of Integer, DateTime)
        Dim buf() As Byte

        buf = GetBuffer(netID)

        If buf Is Nothing Then
            Return Nothing
        End If

        Dim iYear As Integer
        Dim iMonth As Integer
        Dim iDay As Integer
        Dim iIndex As Integer
        Dim dic As New Dictionary(Of Integer, DateTime)

        Dim CurPos As Integer

        CurPos = buf(500) '当前正准备写的区域时间索引

        For i As Integer = 0 To HIST_ARENA_INTERVAL - 1  '先上传当前区域的下一个区域的数据,以免在下位机继续写的过程中区域数据被覆盖,造成读取的数据不一致的情况
            iIndex = (CurPos + i) Mod HIST_ARENA_INTERVAL
            iYear = buf(401 + iIndex * 3 + 0) + 1900
            iMonth = buf(401 + iIndex * 3 + 1)
            iDay = buf(401 + iIndex * 3 + 2)

            'iYear = buf(401 + 3 * i + 0) + 1900
            'iMonth = buf(401 + 3 * i + 1)
            'iDay = buf(401 + 3 * i + 2)

            If iYear * iMonth * iDay = 0 Then  '该区域尚未写入数据
                Continue For
            End If

            If iYear = 255 OrElse iMonth = 255 OrElse iDay = 255 Then  '该区域时间未进行初始化
                Continue For
            End If

            'dic.Add(i, New DateTime(iYear, iMonth, iDay))
            dic.Add(iIndex, New DateTime(iYear, iMonth, iDay))
        Next
        Return dic
    End Function

    ''' <summary>
    ''' 判断指定子控（netID)的年、月、日的历史数据是否存在
    ''' </summary>
    ''' <param name="dt"></param>
    ''' <returns>返回指定日期所在的Block</returns>
    ''' <remarks></remarks>
    Public Shared Function CheckHistoryDataYearMonthDay(ByVal netid As Byte, ByVal dt As DateTime) As Integer
        Dim dic As IDictionary(Of Integer, DateTime)
        dic = GetHistoryDataYearMonth(netid)

        If dic Is Nothing Then
            Return -1
        End If

        '指定日期的历史数据所在页
        Dim pageIndex As Integer = -1

        Dim dtTemp As DateTime
        For Each item As KeyValuePair(Of Integer, DateTime) In dic
            dtTemp = item.Value
            If dtTemp.Year = dt.Year AndAlso dtTemp.Month = dt.Month AndAlso dtTemp.Day = dt.Day Then
                pageIndex = item.Key * HIST_PLANPAGECOUNT_EACHAREA + (dt.Hour * 3600 + dt.Minute * 60 + dt.Second) \ (HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE)
                Exit For
            End If

        Next
        Return pageIndex
    End Function

    ''' <summary>
    ''' 读取断电现场数据－原始数据
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function GetBuffer(ByVal netID As Byte) As Byte()
        If _htBuf.Contains(netID) Then
            Return _htBuf.Item(netID)
        End If

        Dim buf() As Byte
        buf = ReadPowerTime(netID)

        If _htBuf.Contains(netID) Then
            Return _htBuf.Item(netID)
        End If

        If buf IsNot Nothing Then
            _htBuf.Add(netID, buf)
        End If

        Return buf

    End Function

    ''' <summary>
    ''' 读取指定设备的断电现场数据（1页510字节的数据）
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function ReadPowerTime(ByVal netID As Byte) As Byte()
        ' ''Threading.Thread.Sleep(5000)

        Dim buf(510) As Byte

        '读取前半页
        Dim b1() As Byte
        b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, _pageAddress, 1)

        If b1 Is Nothing Then
            Return Nothing
        End If
        Array.Copy(b1, 0, buf, 0, 255)

        '读取后半页
        Dim b2() As Byte
        b2 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, _pageAddress, 2)
        If b2 Is Nothing Then
            Return Nothing
        End If
        Array.Copy(b2, 0, buf, 255, 255)

        Return buf
    End Function
 

    ''' <summary>
    ''' 判断指定设备、指定日期的历史数据是否有效
    ''' </summary>
    ''' <param name="netID">子控的网络编号</param>
    ''' <param name="dt">历史数据的日期（年月日小时）</param>
    ''' <returns>True表示历史数据有效，False表示历史数据无效（时间在断电期间）</returns>
    ''' <remarks></remarks>
    Public Shared Function HistoryDataValidate(ByVal netID As Byte, ByVal dt As DateTime) As Boolean
        Dim l As IList(Of PowerTimeItem)

        '获取指定设备的断电现场数据
        l = GetPowerTimeList(netID)

        If l Is Nothing Then
            Return False
        End If

        '是否为断电期间的标志
        Dim bFound As Boolean = False

        '循环所有断电现场数据，判断指定日期是否在断电期间
        For Each item As PowerTimeItem In l
            If dt > item.StartTime AndAlso dt < item.EndTime Then
                bFound = True
                Exit For
            End If
        Next

        Return Not bFound
    End Function

    ''' <summary>
    ''' 清空“断电现场”缓存数据
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub ClearBuffer()
        _ht.Clear()
        _htBuf.Clear()
    End Sub

End Class
